﻿using LitJson;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
using HeerLauncherCoreLibrary.Tool;


namespace HeerLauncherCoreLibrary
{
    public class MinecraftStartHelper
    {
        public string NativePath = Directory.GetCurrentDirectory() + "\\.minecraft";
        private readonly string mainClass;
        private readonly string verjarPath = string.Empty;
        private readonly string vernativesPath = String.Empty;

        /// <summary>
        /// 通过版本进行实例化。
        /// 顺便解析各种参数。
        /// </summary>
        /// <param name="version"></param>
        public MinecraftStartHelper(string version)
        {
            verjarPath = NativePath + "\\versions\\" + version + "\\" + version + ".jar";
            vernativesPath = NativePath + "\\versions\\" + version + "\\" + version + "-natives";
            verList = new List<MinecraftVersion>();
            libs = new List<Library>();

            var version2 = version;
            var jsonText = new StreamReader(NativePath + "\\versions\\" + version2 + "\\" + version2 + ".json").ReadToEnd();
            JsonData json = JsonMapper.ToObject(jsonText);
            MinecraftVersion mv = JsonMapper.ToObject<MinecraftVersion>(jsonText);
            mainClass = json["mainClass"].ToString();
            verList.Add(mv);
            if (json.Keys.Contains("inheritsFrom"))
            {
                isOriginal = true;
            }
            while (json.Keys.Contains("inheritsFrom"))
            {
                version2 = json["inheritsFrom"].ToString();
                jsonText = new StreamReader(NativePath + "\\versions\\" + version2 + "\\" + version2 + ".json").ReadToEnd();
                json.Clear();
                json = JsonMapper.ToObject(jsonText);
                mv = JsonMapper.ToObject<MinecraftVersion>(jsonText);
                verList.Add(mv);
            }
            baseVersion = mv;
            //把所有层次版本搞出来

            foreach (MinecraftVersion item in verList)
            {
                libs.AddRange(item.libraries);
            }

            getLatestLibFromLibList();
            gettrueLibsAndnativesLibs(libs);
        }

        public MinecraftVersion baseVersion { get; set; }

        /// <summary>
        /// 是否是单一层版本
        /// </summary>
        public bool isOriginal { get; set; }

        public List<Library> libs { get; set; }
        /// <summary>
        /// 需要解压的natives
        /// </summary>
        public List<Library> nativesLibs { get; set; }
        /// <summary>
        /// 需要启动的支持库
        /// </summary>
        public List<Library> trueLibs { get; set; }
        /// <summary>
        /// 启动该版本需要包含的所有版本
        /// </summary>
        public List<MinecraftVersion> verList { get; set; }

        private string AssemblyParameters(LauncherGameInfo launcherGameInfo, LauncherJavaInfo launcherJavaInfo, LauncherPlayerInfo launcherPlayerInfo, LauncherInfo launcherInfo)
        {
            string mem = string.Format(" -Xmn128m -Xmx{0}m", launcherJavaInfo.memory.ToString());
            string gameargs = String.Empty;
            string jvmargs = String.Empty;

            foreach (var item in baseVersion.arguments.game)
            {
                if (item.GetType() == typeof(string))
                {
                    gameargs += " " + item.ToString();
                }
            }
            foreach (var item in baseVersion.arguments.jvm)
            {
                if (item.GetType() == typeof(string))
                {
                    jvmargs += " " + item.ToString();
                }
            }

            gameargs = gameargs.Trim();

            string windows_arg2 = "-XX:HeapDumpPath\u003dMojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump";
            //替换
            gameargs = gameargs.Replace("${auth_player_name}", launcherPlayerInfo.playerName);
            gameargs = gameargs.Replace("${version_name}", verList[0].id);
            gameargs = gameargs.Replace("${game_directory}", NativePath);
            gameargs = gameargs.Replace("${assets_root}", NativePath + "\\asstes");
            gameargs = gameargs.Replace("${assets_index_name}", baseVersion.assets);
            gameargs = gameargs.Replace("${auth_uuid}", launcherPlayerInfo.uuid);
            gameargs = gameargs.Replace("${auth_access_token}", launcherPlayerInfo.token);
            gameargs = gameargs.Replace("${user_type}", "mojang");
            gameargs = gameargs.Replace("${version_type}", baseVersion.type);

            string cp = "";
            foreach (var item in trueLibs)
            {
                cp += "\"" + NativePath + "\\libraries\\" + getPathFromLibName(NativePath, item.name) + "\";";
            }
            cp += "\"" + NativePath + "\\versions\\" + baseVersion.id + "\\" + baseVersion.id + ".jar\"";
            // cp.TrimEnd(';');
            jvmargs = jvmargs.Replace("${classpath}", cp.Trim());
            jvmargs = jvmargs.Replace("/", "\\");
            jvmargs = jvmargs.TrimEnd(';');
            //替换
            jvmargs = jvmargs.Replace("${natives_directory}", vernativesPath);
            jvmargs = jvmargs.Replace("${launcher_name}", launcherInfo.LauncherName);
            jvmargs = jvmargs.Replace("${launcher_version}", launcherInfo.LauncherVersion);

            return windows_arg2 + mem + jvmargs + " " + getmainClass() + " " + gameargs;
        }
        /// <summary>
        /// 开始启动
        /// </summary>
        /// <param name="launcherAssemblyInfo"></param>
        /// <returns>启动进程</returns>
        public Process BeginLaunch(LauncherAssemblyInfo launcherAssemblyInfo)
        {
            var a = getLauncherCmd(launcherAssemblyInfo);
            Process p = new Process();
            p.StartInfo.FileName = "cmd.exe";
            p.StartInfo.UseShellExecute = false;    //是否使用操作系统shell启动
            p.StartInfo.RedirectStandardInput = true;//接受来自调用程序的输入信息
            p.StartInfo.RedirectStandardOutput = false;//由调用程序获取输出信息
            p.StartInfo.RedirectStandardError = true;//重定向标准错误输出
            p.StartInfo.CreateNoWindow = true;
            p.Start();
            p.StandardInput.WriteLine(a);
            return p;
        }

        /// <summary>
        /// 获取启动命令行
        /// </summary>
        /// <param name="launcherAssemblyInfo"></param>
        /// <returns></returns>
        public string getLauncherCmd(LauncherAssemblyInfo launcherAssemblyInfo)
        {
            return "\"" + launcherAssemblyInfo.launcherJavaInfo.javaPath + "\" " + AssemblyParameters(launcherAssemblyInfo.launcherGameInfo, launcherAssemblyInfo.launcherJavaInfo, launcherAssemblyInfo.launcherPlayerInfo, launcherAssemblyInfo.launcherInfo);
        }

        /// <summary>
        /// 获取主类
        /// </summary>
        /// <returns></returns>
        public string getmainClass()
        {
            return mainClass;
        }

        private static string getPathFromLibName(string NativePath, string name)
        {
            string[] ed = name.Split(':');
            string[] ed2 = ed[0].Split('.');
            string returnc = "";
            foreach (string item in ed2)
            {
                returnc += item + "/";
            }
            returnc = returnc + ed[1] + "/" + ed[2] + "/" + ed[1] + "-" + ed[2] + ".jar";
            string jarPath = NativePath + "\\libraries\\" + returnc;
            return returnc;
        }

        private void getLatestLibFromLibList()
        {
            var libs2 = libs;
            List<cuteLibNameIncVersion> lc = new List<cuteLibNameIncVersion>();//持久list
            List<cuteLibNameIncVersion> rList = new List<cuteLibNameIncVersion>();//最后的List
            foreach (var item in libs2)
            {
                char c = ':';
                var spiltedName = item.name.Split(c);
                cuteLibNameIncVersion temp = new cuteLibNameIncVersion();
                temp.name = spiltedName[0] + spiltedName[1];
                temp.version = Int32.Parse(Regex.Replace(spiltedName[2], @"[^\d]*", ""));
                temp.theLib = item;
                lc.Add(temp);
            }
            //上面把每个lib分析了下。
            var has = false;
            foreach (var item in lc)
            {
                foreach (var item2 in lc)
                {
                    if (item.name == item2.name && item.version > item2.version)
                    {
                        rList.Add(item);
                        has = true;
                        break;
                    }
                    else if (item.name == item2.name && item.version < item2.version)
                    {
                        has = true;
                        rList.Add(item2);
                        break;
                    }
                    else
                    {
                        has = false;
                    }
                }
                if (has != true) { rList.Add(item); }
                has = false;
            }//该死的循环，别管。
            libs.Clear();
            foreach (var item in rList)
            {
                if (item.theLib.rules != null)
                {
                    if (item.theLib.rules[0].os.name == "windows")
                    {
                        libs.Add(item.theLib);
                    }
                    else
                    {
                    }
                }
                else
                {
                    libs.Add(item.theLib);
                }
            }
        }//lib独立版本比较

        private void gettrueLibsAndnativesLibs(List<Library> libraries)
        {
            trueLibs = new List<Library>();
            nativesLibs = new List<Library>();
            foreach (var item in libs)
            {
                if (item.natives != null)
                {
                    nativesLibs.Add(item);
                }
                else
                {
                    trueLibs.Add(item);
                }
            }
        }

        public void unzipNativesLibs() {
            if (Directory.Exists(vernativesPath)) { Directory.Delete(this.vernativesPath, true); };
            foreach (var item in nativesLibs)
            {
                var b = NativePath + "\\libraries\\" + item.downloads.classifiers.__invalid_name__natives_windows.path;
                b = b.Replace("/", "\\");
                ZipHelper.unzip(NativePath+"\\libraries\\"+ item.downloads.classifiers.__invalid_name__natives_windows.path,vernativesPath);
            }

        }
    }

    internal class cuteLibNameIncVersion
    {
        public string name;
        public Library theLib;
        public int version;
    }
}